package com.atguigu.study.bootredis.util;

import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;

import java.lang.reflect.Type;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Map;

/**
 * JSON工具类（过滤null字段，可指定日期格式）
 *
 * @author
 */
public class JSON {
    /**
     * 标准日期格式
     */
    public static final String DEFAULT_DATE_PATTERN = "yyyyMMddHHmmss";

    /**
     * 默认实现 (java.util.Date使用标准日期格式的字符串表示)
     */
    private static JSON DEFAULT = build(DEFAULT_DATE_PATTERN);

    /**
     * JACKSON转换器
     */
    private ObjectMapper jacksonMapper;

    /**
     * 构造函数
     */
    private JSON() {}

    /**
     * 获得默认实现
     *
     * @return
     */
    public static JSON getDefault() {
        return DEFAULT;
    }

    /**
     * 指定日期格式并构建JSON对象
     *
     * @param datePattern 日期格式
     */
    public static JSON newInstance(String datePattern) {
        if (DEFAULT_DATE_PATTERN.equals(datePattern)) {
            return DEFAULT;
        }

        return build(datePattern);
    }

    /**
     * 构造JSON对象
     *
     * @param datePattern 日期格式
     */
    private static JSON build(String datePattern) {
        JSON json = new JSON();

        ObjectMapper jacksonMapper = new ObjectMapper();
        jacksonMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        jacksonMapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
        jacksonMapper.setSerializationInclusion(Include.NON_NULL);

        if (datePattern != null) {
            DateFormat dateFormat = new SimpleDateFormat(datePattern);
            jacksonMapper.setDateFormat(dateFormat);
        }

        json.jacksonMapper = jacksonMapper;
        return json;
    }

    /**
     * 将对象转换为JSON字符串
     *
     * @param obj
     * @return
     */
    public String toJSONString(Object obj) {
        try {
            return jacksonMapper.writeValueAsString(obj);
        } catch (Exception e) {
            throw new RuntimeException("To json string error", e);
        }
    }

    /**
     * 将JSON字符串转换为对象
     *
     * @param json
     * @param clazz
     * @return
     */
    public <T> T parseToObject(String json, Class<T> clazz) {
        try {
            return jacksonMapper.readValue(json, clazz);
        } catch (Exception e) {
            throw new RuntimeException("Parse json str to object error", e);
        }
    }

    /**
     * 将JSON字符串转换为对象
     *
     * @param json
     * @param type
     * @return
     */
    public <T> T parseToObject(String json, final Type type) {
        try {
            return jacksonMapper.readValue(json, new TypeReference<T>() {
                @Override
                public Type getType() {
                    return type;
                }
            });
        } catch (Exception e) {
            throw new RuntimeException("Parse json str to object error", e);
        }
    }
    /**
     * 将JSON字符串转换为对象List
     *
     * @param json
     * @param clazz
     * @return
     */
    public <T> List<T> parseToList(String json, Class<T> clazz) {
        List<T> list = null;
        try {
            JavaType javaType = jacksonMapper.getTypeFactory()
                    .constructCollectionType(List.class, clazz);// clz.selGenType().getClass()
            list = jacksonMapper.readValue(json, javaType);
        } catch (Exception e) {
            throw new RuntimeException("Parse json str to List error", e);
        }
        return list;
    }

    /**
     * 将JSON字符串转换为Map
     *
     * @param json
     * @param clazzKey
     * @param clazzValue
     * @return
     */
    public <K,T> Map<K, T> parseToMap(String json, Class<K> clazzKey, Class<T> clazzValue) {
        try {
            JavaType javaType = jacksonMapper.getTypeFactory().constructMapType(Map.class, clazzKey, clazzValue);
            return jacksonMapper.readValue(json, javaType);
        } catch (Exception e) {
            throw new RuntimeException("Parse json str to object error", e);
        }
    }
}
